﻿using System;
using System.Collections.Generic;
using System.Text;

using System.IO;
using System.Xml;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace gTray
{
    [Serializable]
    public class EncryptedCredential : ISerializable
    {
        public string Username { get; private set; }
        public string Password { get; private set; }

        public EncryptedCredential(string user, string pass)
        {
            this.Username = user;
            this.Password = pass;
        }

        public EncryptedCredential(SerializationInfo info, StreamingContext context)
        {
            this.Username = (string)info.GetValue("Username", typeof(string));
            this.Password = (string)info.GetValue("Password", typeof(string));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Username", this.Username);
            info.AddValue("Password", this.Password);
        }
    }

    public class SettingService 
    {
        private Dictionary<string, object> _Settings;

        private string _SettingsPath;

        #region Singletone Pattern Code
        private static SettingService _Instance = null;
        static readonly object _PadLock = new object();

        public static SettingService Instance
        {
            get
            {
                lock (_PadLock)
                {
                    if (_Instance == null)
                    {
                        _Instance = new SettingService();
                    }
                    return _Instance;
                }
            }
        }
        #endregion

        public bool RunAtStartup
        {
            get
            {
                return Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run").GetValue("gTray", null) != null;
            }
            set
            {
                Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
                if (value == true)
                {
                    key.SetValue("gTray", System.Windows.Forms.Application.ExecutablePath);
                }
                else
                {
                    key.DeleteValue("gTray",false);
                }
            }
        }

        #region Recheck Interval
        public const int RecheckIntervalDefault = 120;
        private const string RecheckKey = "RecheckInterval";
        public int RecheckIntervalSeconds 
        {
            get { return (int)_Settings[RecheckKey]; }
            set { _Settings[RecheckKey] = value; }
        }
        #endregion

        #region NotificationInterval
        public const int NotificationIntervalDefault = 4;
        private const string NotificationKey = "NotificationInterval";
        public int NotificationIntervalSeconds
        {
            get { return (int)_Settings[NotificationKey]; ; }
            set { _Settings[NotificationKey] = value; }
        }
        #endregion

        #region Do Save Credentials
        public const bool DoSaveCredentialsDefault = false;
        private const string DoSaveKey = "DoSaveCredentials";
        public bool DoSaveCredentials
        {
            get { return (bool)_Settings[DoSaveKey]; }
            set { _Settings[DoSaveKey] = value; }
        }
        #endregion

        #region Do Auto Login
        public const bool DoAutoLoginDefault = false;
        private const string DoAutoKey = "DoAutoLogin";
        public bool DoAutoLogin
        {
            get { return (bool)_Settings[DoAutoKey]; }
            set 
            { 
                _Settings[DoAutoKey] = value;
                if (value == false)
                    AutoLoginCredential = null;
            }
        }
        #endregion

        #region Usernames
        private const string UsernameKey = "UsernameList";
        public List<string> Usernames
        {
            get { return (List<string>)_Settings[UsernameKey]; ;}
        }

        #endregion

        #region AutoSaveCredential
        private const string AutoLoginKey = "AutoLoginCredential";
        public EncryptedCredential AutoLoginCredential
        {
            get { return (EncryptedCredential)_Settings[AutoLoginKey]; }
            private set 
            { 
                _Settings[AutoLoginKey] = value;
                if (value == null)
                    _Settings.Remove(AutoLoginKey);
            }
        }

        public void AddAutoLoginCredential(string unEncryptUsername, string unEncryptPassword)
        {
           AutoLoginCredential = new EncryptedCredential(
                CryptoService.Encrypt(unEncryptUsername), 
                CryptoService.Encrypt(unEncryptPassword));    
        }

        /// <summary>
        /// Gets the auto login credential as a Network Credential
        /// </summary>
        /// <returns></returns>
        public System.Net.NetworkCredential GetAutoLoginCredential()
        {
            return new System.Net.NetworkCredential(
                CryptoService.Decrypt(AutoLoginCredential.Username),
                CryptoService.Decrypt(AutoLoginCredential.Password));
        }
        #endregion

        private SettingService()
        {
            _Settings = new Dictionary<string, object>();
            _Settings[UsernameKey] = new List<string>();
            
            Load();
        }

        public void Load()
        {
            _SettingsPath = Environment.CurrentDirectory + "\\gTraySettings.dat";

            if (!File.Exists(_SettingsPath))
            {
                CreateNewSettings();
            }

            LoadSettings();
        }

        private void LoadSettings()
        {
            var stream = new FileStream(_SettingsPath, FileMode.Open, FileAccess.Read);

            var formatter = new BinaryFormatter();
            _Settings = (Dictionary<string, object>)formatter.Deserialize(stream);
            stream.Close();

            //Decrypts the usernames for use
            for (int i = 0; i < this.Usernames.Count; i++)
            {
                this.Usernames[i] = CryptoService.Decrypt(this.Usernames[i]);
            }
        }

        private void CreateNewSettings()
        {
            SaveSettings(true);
        }

        /// <summary>
        /// Saves the settings.
        /// </summary>
        public void Save()
        {
            SaveSettings(false);
        }

        private void SaveSettings(bool UseDefaults)
        {
            var stream = new FileStream(_SettingsPath, FileMode.Create, FileAccess.Write);

            if (UseDefaults)
            {
                RecheckIntervalSeconds = RecheckIntervalDefault;
                NotificationIntervalSeconds = NotificationIntervalDefault;
                DoSaveCredentials = DoSaveCredentialsDefault;
                DoAutoLogin = DoAutoLoginDefault;
                Usernames.Clear();
                if (_Settings.ContainsKey(AutoLoginKey))
                    _Settings.Remove(AutoLoginKey);
            }

            //Encrypts the usernames for storage
            for (int i = 0; i < this.Usernames.Count; i++)
			{
			    this.Usernames[i] = CryptoService.Encrypt(this.Usernames[i]);
			}

            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, _Settings);
            stream.Close();

            //Decrypts them for use
            for (int i = 0; i < this.Usernames.Count; i++)
            {
                this.Usernames[i] = CryptoService.Decrypt(this.Usernames[i]);
            }
        }

        /// <summary>
        /// Instantiates this instance. Used for initial instantiation.
        /// </summary>
        internal void Instantiate()
        { }
    }
}
